package com.biye.api.tool.security.service.impl;

import com.biye.api.tool.security.mapper.SecurityMapper;
import com.biye.api.tool.security.service.RbacService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

@Component("rbacService")
public class RbacServiceImpl implements RbacService {

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Value("${server.servlet.context-path:}")
    // 加上半角：号，若没有该配置属性，则变量值为"" 【"".equals(contextPath)为true】
    private String contextPath;

    @Resource
    private SecurityMapper securityMapper;

    protected static List<String> stuUrlList = new ArrayList<>();
    static {
        // 授权访问的Uri
        stuUrlList.add("/common/**");
        stuUrlList.add("/base/**");
        stuUrlList.add("/download/**");
    }

    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        // 获取用户的用户名
        String[] user_info_arr = ((String) authentication.getPrincipal()).split("@");
        String user_id = user_info_arr[0];  // sno or tno
        String user_type = user_info_arr[1];  // stu or tea
        // 当前用户访问的uri
        String accessUri = request.getRequestURI();
        List<String> urls = new ArrayList<>();
        if ( "stu".equals(user_type) ){
            urls = this.stuUrlList;
        }
        if ( "tea".equals(user_type) ){
            urls = securityMapper.findUriListByUserId(user_id);
        }
        if ( !"".equals(contextPath) ){
            // 当前路径除去工程名的uri为，uri e.g. /edu/common/os, contextPath = /edu, now change it to /common/os
            accessUri = accessUri.replace(contextPath, "");
        }
        // 判断：“是否有权限access这个接口”
        System.out.println("the current user " + (String) authentication.getPrincipal() + " want to access a func, its uri ==> " + accessUri);
        System.out.println("urls {}".replace("{}", urls.toString()));
        // 当前请求访问的Uri为（设置成final, urls.stream().anyMatch中的参数要求final）
        final String finalAccessUri = accessUri;
        /*
        非模糊匹配，若要改成模糊匹配请使用String的contains(uri)
        1. /erb/contract/?est.json 匹配/erb/contract/test.json、/erb/contract/aest.json、/erb/contract/best.json, 但不匹配/erb/contract/est.json ；

        2. /erb/contract/*.json 匹配以.json的路径，/erb/contract/a.json、/erb/contract/ab.json、/erb/contract/abcXXX.json

        3. /erb/contract/*  匹配以 /erb/contract/开始的路径，但只能是一级,/erb/contract/a、/erb/contract/abXXX、/erb/contract/a.json、/erb/contract/abXX.json、/erb/contract/a.do、/erb/contract/abXX.do 等

        4.  /**\/contract\/** ，只要路径含有contract就可以匹配，比如：/erb/XXX/contract/a/b/XX、/erb/XXX/contract/a/b/XX.XX 
        ((第4和第5各使用了2个转义符\, 解决javadoc注释问题。真正使用的时候将左边的参照串存入数据库即可，右边的是当前访问路径的真实Uri))
        5. /**\/{contract:[a-z,A-Z]+}\/**, 比如：/erb/XXX/contract/a/b/XX、/erb/XXX/contractXXX/a/b/XX.XX
        */
        return urls.stream().anyMatch(
                url -> antPathMatcher.match(url, finalAccessUri)
        );
        // 当这个方法返回false, 将交由http.exceptionHandling().accessDeniedHandler(myAccessDenied);处理403
    }
}
